#include "algoCG.h"
#include <math.h>
#include <stdio.h>
#include "../common_typedef.h"
#include "rom_LcdFont.h"

#define LCD_STRING_BUF_LEN 128
#define LCD_W 240
#define LCD_H 240
#define BACK_COLOR 0xffff

extern void LCD_DrawPoint(int x, int y, uint16_t color);

void algoCG_DrawLine(CGPoint a, CGPoint b)
{
    int x1 = a.x;
    int y1 = a.y;
    int x2 = b.x;
    int y2 = b.y;
    uint16_t color = a.color;
    uint16_t t;
    int xerr = 0, yerr = 0, delta_x, delta_y, distance;
    int incx, incy, uRow, uCol;
    delta_x = x2 - x1; // 计算坐标增量
    delta_y = y2 - y1;
    uRow = x1; // 画线起点坐标
    uCol = y1;
    if (delta_x > 0)
        incx = 1; // 设置单步方向
    else if (delta_x == 0)
        incx = 0; // 垂直线
    else
    {
        incx = -1;
        delta_x = -delta_x;
    }
    if (delta_y > 0)
        incy = 1;
    else if (delta_y == 0)
        incy = 0; // 水平线
    else
    {
        incy = -1;
        delta_y = -delta_y;
    }
    if (delta_x > delta_y)
        distance = delta_x; // 选取基本增量坐标轴
    else
        distance = delta_y;
    for (t = 0; t < distance + 1; t++)
    {
        LCD_DrawPoint(uRow, uCol, color); // 画点
        xerr += delta_x;
        yerr += delta_y;
        if (xerr > distance)
        {
            xerr -= distance;
            uRow += incx;
        }
        if (yerr > distance)
        {
            yerr -= distance;
            uCol += incy;
        }
    }
}

void lcd_draw_line(int x1, int y1, int x2, int y2)
{
    algoCG_DrawLine((CGPoint){x1, y1, 0xffff},
                    (CGPoint){x2, y2, 0xffff});
}

void lcd_draw_point(int x, int y)
{
    LCD_DrawPoint(x, y, 0xffff); // 画点
}
/**
 * display a rectangle on the lcd.
 *
 * @param   x1      x1 position
 * @param   y1      y1 position
 * @param   x2      x2 position
 * @param   y2      y2 position
 *
 * @return  void
 */
void lcd_draw_rectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
{
    lcd_draw_line(x1, y1, x2, y1);
    lcd_draw_line(x1, y1, x1, y2);
    lcd_draw_line(x1, y2, x2, y2);
    lcd_draw_line(x2, y1, x2, y2);
}

/**
 * display a circle on the lcd.
 *
 * @param   x       x position of Center
 * @param   y       y position of Center
 * @param   r       radius
 *
 * @return  void
 */
void lcd_draw_circle(uint16_t x0, uint16_t y0, uint8_t r)
{
    int a, b;
    int di;
    a = 0;
    b = r;
    di = 3 - (r << 1);
    while (a <= b)
    {
        lcd_draw_point(x0 - b, y0 - a);
        lcd_draw_point(x0 + b, y0 - a);
        lcd_draw_point(x0 - a, y0 + b);
        lcd_draw_point(x0 - b, y0 - a);
        lcd_draw_point(x0 - a, y0 - b);
        lcd_draw_point(x0 + b, y0 + a);
        lcd_draw_point(x0 + a, y0 - b);
        lcd_draw_point(x0 + a, y0 + b);
        lcd_draw_point(x0 - b, y0 + a);
        a++;
        // Bresenham
        if (di < 0)
            di += 4 * a + 6;
        else
        {
            di += 10 + 4 * (a - b);
            b--;
        }
        lcd_draw_point(x0 + a, y0 + b);
    }
}

void lcd_show_char(uint16_t x,uint16_t y,uint8_t num, uint16_t color, uint8_t sizey)
{
    uint8_t temp,sizex,t;
    uint16_t i,TypefaceNum;//一个字符所占字节大小
    uint16_t x0=x;
    sizex=sizey/2;
    TypefaceNum=(sizex/8+((sizex%8)?1:0))*sizey;
    num=num-' ';    //得到偏移后的值
    for(i=0;i<TypefaceNum;i++)
    {
        if(sizey == 12)temp=ascii_1206[num][i];		       //调用6x12字体
        else if(sizey == 16)temp=ascii_1608[num][i];		 //调用8x16字体
        else if(sizey == 24)temp=ascii_2412[num][i];		 //调用12x24字体
        else if(sizey == 32)temp=ascii_3216[num][i];		 //调用16x32字体
        else return;
        for(t = 0; t < 8; t++)
        {
            if (temp & (0x01 << t)) {
                LCD_DrawPoint(x,y,color);//画一个点
            } else {
                LCD_DrawPoint(x,y,BACK_COLOR); // 绘制背景
            }
            x++;
            if((x - x0) == sizex) {
                x = x0;
                y++;
                break;
            }
        }
    }
}

/**
 * display the number on the lcd.
 *
 * @param   x       x position
 * @param   y       y position
 * @param   num     number
 * @param   len     length of number
 * @param   size    size of font
 *
 * @return  void
 */
void lcd_show_num(uint16_t x, uint16_t y, uint32_t num, uint8_t len, uint32_t size)
{
    lcd_show_string(x, y, size, "%d", num);
}

/**
 * display the string on the lcd.
 *
 * @param   x       x position
 * @param   y       y position
 * @param   size    size of font
 * @param   p       the string to be display
 *
 * @return   0: display success
 *          -1: size of font is not support
 */
uint32_t lcd_show_string(uint16_t x, uint16_t y, uint32_t size, const char *fmt, ...)
{

     if (size != 16 && size != 24 && size != 32)
     {
         return ERR_FAILURE;
     }

     va_list args;
     char buf[LCD_STRING_BUF_LEN] = {0};

     va_start(args, fmt);
     vsprintf((char *)buf, fmt, args);
     va_end(args);


     uint8_t *p = (uint8_t*)buf;
     while (*p != '\0')
     {
         if (x > LCD_W - size / 2)
         {
             x = 0;
             y += size;
         }
         if (y > LCD_H - size)
         {
             y = x = 0;
         }
         lcd_show_char(x, y, *p, 0xF800, size);
         x += size / 2;
         p++;
     }

     return ERR_SUCCESS;
}

/**
 * display the image on the lcd.
 *
 * @param   x       x position
 * @param   y       y position
 * @param   length  length of image
 * @param   wide    wide of image
 * @param   p       image
 *
 * @return   0: display success
 *          -1: the image is too large
 */
uint32_t lcd_show_image(uint16_t x, uint16_t y, uint16_t length, uint16_t wide, const uint8_t *p)
{
    // RT_ASSERT(p);

    // if (x + length > LCD_W || y + wide > LCD_H)
    // {
    //     return ERR_FAILURE;
    // }

    // lcd_address_set(x, y, x + length - 1, y + wide - 1);

    // LCD_DC_WriteGPIO(GPIO_SET);
    // rt_spi_send(spi_dev_lcd, p, length * wide * 2);

    return ERR_SUCCESS;
}

void algoCG_Fill(CGPoint leftTop, CGPoint rightBottom)
{
    int x1 = leftTop.x;
    int y1 = leftTop.y;
    int x2 = rightBottom.x;
    int y2 = rightBottom.y;
    uint16_t color = leftTop.color;
    for (int y = y1; y < y2; y++) {
        CGPoint lineLeft = {x1, y, color};
        CGPoint lineRight = {x2, y, color};
        algoCG_DrawLine(lineLeft, lineRight);
    }
}
